#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>

// #define ERR			-1
// #define FILE_EXIST	-2

#define TEST_COUNT 100

enum E_ERRNUM
{
	FILE_EXIST	= -3,
	FILE_FAIL,
	ERR,

	FALSE		= 0,
	TRUE		= 1,
};

static int fileSym = 0;
static char* testFileName = 0;

// 初始化文件
int Init();
// 结束清理
void Fini();
// 运行写入测试
void RunWriteTest();
// 运行读取测试
void RunReadTest();

int main( int argc, char* argv[] )
{
	int i=0;
	int nRet = FALSE;
	for( i=1; i<argc; ++i )
	{
		printf( "%s\n", argv[i] );
	}

	if( argc > 1 )
	{
		testFileName = argv[1];
		nRet = Init();
		if( nRet == TRUE )
		{
			RunWriteTest();
			RunReadTest();
			Fini();
		}
	}
	return 0;
}

int OpenFile( char* filename )
{
	/* 文件描述符 */
	int fdes = ERR;

	if( !filename )
		return ERR;

	/* 测试文件是否存在 */
	fdes = open( filename, O_RDONLY );
	if( fdes > 0 )
	{
		fprintf( stderr, "文件已存在.\n" );
		return FILE_EXIST;
	}

	fdes = open( filename, O_RDWR | O_CREAT | O_DSYNC );
	if( fdes <= 0 )
	{
		fprintf( stderr, "创建文件失败.\n" );
		return FALSE;
	}
	return fdes;
}

void OutputTime( char* title, struct timeval* beg, struct timeval* end )
{
	struct timeval val;

	if( !title || !beg || !end )
		return;

	val.tv_sec = end->tv_sec - beg->tv_sec;
	val.tv_usec= end->tv_usec- beg->tv_usec;
	if( val.tv_usec < 0 )
	{
		--val.tv_sec;
		val.tv_usec *= -1;
	}
	printf( "==================================================\n" );
	printf( "%s %dM 用时 : %lu.%lu S\n", title, TEST_COUNT, val.tv_sec, val.tv_usec );
	double fusec = val.tv_usec;
	while( fusec > 1.0f )
	{
		fusec /= 10.0f;
	}
	double fSpeed = TEST_COUNT / (val.tv_sec*1.0f+fusec);
	printf( "%s 速度 %.2fMB/s\n", title, fSpeed );
	printf( "==================================================\n" );
}

int Init()
{
	if( !testFileName )
		return FALSE;
	fileSym = OpenFile( testFileName );

	return fileSym > 0 ? TRUE : FALSE;
}

void Fini()
{
	if( fileSym > 0 )
	{
		close( fileSym );
		fileSym = 0;
	}
	// remove( testFileName );
	unlink( testFileName );
}

void RunWriteTest()
{
	struct timeval tBeg, tEnd;
	int	  nRet = 0;
	char *pBuf = NULL;
	int	  nLen = 1024 * 1024;
	ssize_t writeLen = 0;

	if( fileSym <= 0 )
		return ;
	/* 写入 500M 的数据然后给出使用的时间 */
	pBuf = (char*)malloc( 1024 * 1024 );

	nRet = gettimeofday( &tBeg, NULL );
	if( nRet != 0 )
		return;

	if( pBuf )
	{
		int i = 0;
		for( i=0; i<TEST_COUNT; ++i )
		{
			memset( pBuf, 0x7F, nLen );
			writeLen = write( fileSym, pBuf, nLen );
			if( writeLen == -1 )
			{
				fprintf( stderr, "写入失败." );
				return;
			}
		}
	}

	nRet = gettimeofday( &tEnd, NULL );
	if( nRet != 0 )
		return;

	free( pBuf );

	OutputTime( "写入", &tBeg, &tEnd );
}

void RunReadTest()
{
	struct timeval tBeg, tEnd;
	int	  nRet = 0;
	char *pBuf = NULL;
	int	  nLen = 1024 * 1024;
	ssize_t readLen = 0;
	off_t	currPos;

	if( fileSym <= 0 )
		return ;

	/* 读取 500M 的数据然后计算使用时间 */
	if( fileSym <= 0 )
		return;

	currPos = lseek( fileSym, 0, SEEK_SET );
	pBuf = (char*)malloc( 1024 * 1024 );

	nRet = gettimeofday( &tBeg, NULL );
	if( nRet != 0 )
		return;

	if( pBuf )
	{
		int i = 0;
		for( i=0; i<TEST_COUNT; ++i )
		{
			memset( pBuf, 0, nLen );
			readLen = read( fileSym, pBuf, nLen );
			if( readLen == -1 )
			{
				fprintf( stderr, "读取失败." );
				return;
			}
		}
	}

	nRet = gettimeofday( &tEnd, NULL );
	if( nRet != 0 )
		return;

	free( pBuf );

	OutputTime( "读取", &tBeg, &tEnd );
}

